/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package client;

import client.ObjectItem.ItemBase;
import com.jme3.asset.plugins.ZipLocator;
import com.jme3.math.Vector3f;
import de.lessvoid.nifty.Nifty;
import de.lessvoid.nifty.controls.Console;
import de.lessvoid.nifty.controls.ConsoleCommands;
import de.lessvoid.nifty.controls.ConsoleCommands.ConsoleCommand;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

/**
 *
 * @author Ben
 */
public class ConCmd
{
    boolean isBloom = true;
    boolean isSSAO = true;
    ConsoleCommands conCmd;
    ConsoleCommand tp;
    ConsoleCommand help;
    ConsoleCommand ssao;
    ConsoleCommand bloom;
    ConsoleCommand loadMap;
    ConsoleCommand build;
    ConsoleCommand loc;
    ConsoleCommand addZip;
    ConsoleCommand LoadModel;
    ConsoleCommand spawnItem;
    ConsoleCommand createServer;
    ConsoleCommand connect;
    ConsoleCommand sendChat;
    ConsoleCommand listnodes;
    ConsoleCommand save_command;
    ConsoleCommand load_command;
    ConsoleCommand lookat;
    ConsoleCommand noclip;
    ArrayList<ZipFile> zips = new ArrayList<ZipFile>();
    static LundWidget lund = new LundWidget();

    /*
    SimpleCommand:
    tutorial command, echoes back args, unused
    */
    private class SimpleCommand implements ConsoleCommand 
    {

        @Override
        public void execute(final String[] args) 
        {
            System.out.println(args[0]); // this is always the command (in this case 'simple')
            if (args.length > 1) 
            {
                for (String a : args) 
                {
                    System.out.println(a);
                }
            }
        }
    }

    /*
    ShowCommand:
    lists all commands, no explanation needed
    */
    private class ShowCommand implements ConsoleCommand 
    {
        @Override
        public void execute(final String[] args) 
        {
            List<String> cmds = conCmd.getRegisteredCommands();
            for(int i = 0; i < cmds.size(); i++ )
            {
                lund.printConsoleInfo(cmds.get(i));
            }
        }
    }
    
    
    /*
    Teleport:
    specific check here to prevent null exceptions and teleporting the user into the void, otherwise uses the
    player_teleport function to move them to the specified locaction, documented in object_player.java
    */
    private class Teleport implements ConsoleCommand
    {
        @Override
        public void execute(final String[] args)
        {
            if(args.length > 4 || args.length < 4)
            {
                lund.printConsoleError("Incorrect parameters to teleport, needs tp xcoord ycoord zcoord!");
            }
            else
            {
                if (args.length == 4) 
                {
                    lund.printConsoleInfo("Teleporting to: " + args[1] + "," + args[2] + "," + args[3]);
                    Main.player.playerTeleport(new Vector3f(Integer.parseInt(args[1]), Integer.parseInt(args[2]), Integer.parseInt(args[3])));
                }
            }
        }
    }
    
    /*
    toggleBloom:
    simple switch for bloom
    */
    private class toggleBloom implements ConsoleCommand
    {
        @Override
        public void execute(final String[] args)
        {
            if(isBloom == true)
            {
                Main.lights.removeBloom();
                lund.printConsoleInfo("Bloom is now off.");
                isBloom = false;
            }
            else if (isBloom == false)
            {
                Main.lights.addBloom();
                lund.printConsoleInfo("Bloom is now on.");
                isBloom = true;
            }
        }
    }
    
    /*
    toggleSSAO:
    simple switch for ssao
    */
    private class toggleSSAO implements ConsoleCommand
    {
        @Override
        public void execute(final String[] args)
        {
            if(isSSAO == true)
            {
                Main.lights.removeSSAO();
                lund.printConsoleInfo("SSAO is now off.");
                isSSAO = false;
            }
            else if (isSSAO == false)
            {
                Main.lights.addSSAO();
                lund.printConsoleInfo("SSAO is now on.");
                isSSAO = true;
            }
        }
    }
    
    private class listNodes implements ConsoleCommand
    {
        @Override
        public void execute(final String[] args)
        {
            for(int i = 0; i < Main.appref.getRootNode().getChildren().size(); i++)
            {
                lund.printConsoleInfo(Main.appref.getRootNode().getChild(i).getName());
            }
            for(int i = 0; i < Main.rendernode.getChildren().size(); i++)
            {
                lund.printConsoleInfo(Main.rendernode.getChild(i).getName());
            }
        }
    }
    
    /*
    loadMap:
    again with the length check, and then loading up the maps.zip, check it's validity and then attempt
    to load the given map of the specified type.
    */
    private class loadMap implements ConsoleCommand
    {
        @Override
        public void execute(final String[] args)
        {
            if(args.length > 4  || args.length < 4)
            {
                lund.printConsoleError("Incorrect parameters, needs loadmap");
                lund.printConsoleError("heightmap/scene (texturemap/null) 1/0!");
            }
            else
            {
                ZipFile zip = null;
                try
                {
                    zip = new ZipFile("maps.zip");
                } 
                catch (IOException ex)
                {
                    lund.printConsoleWarning("Your map zip is invalid or corrupted.");
                }
                ZipEntry ze = zip.getEntry(args[1]);
                if (ze != null && args[3].equals("1"))
                {
                    TerrainControl.heightMapImage = lund.loadTexture(args[1].toString());
                    lund.printConsoleInfo("Loaded map:" + args[1]);
                    if (args.length > 2)
                    {
                        ZipEntry zi = zip.getEntry(args[2]);
                        if (zi != null)
                        {
                            lund.printConsoleInfo(" with texture map: " + args[2]);
                            TerrainControl.matRock.setTexture("AlphaMap", lund.loadTexture(args[2]));
                        } 
                        else
                        {
                            lund.printConsoleInfo("Invalid texture map " + args[2] + " specified, using old.");
                        }
                    }
                    TerrainControl.reloadTerrain(1);
                } 
                else if (ze != null && args[3].equals("0"))
                {
                    Main.gameScene = Main.appref.getAssetManager().loadModel(args[1].toString());
                    lund.printConsoleInfo("Loaded map:" + args[1]);
                    TerrainControl.reloadTerrain(0);
                } 
                else
                {
                    lund.printConsoleWarning("The requested map: " + args[1] + " does not exist.");
                }
            }
        }
    }
    
    /*
    loadModel:
    length check, repeat through entries in all registered zip files checking their names against given args, passing them if
    they are true and then spawning if found
    */
    private class loadModel implements ConsoleCommand
    {
        @Override
        public void execute(final String[] args)
        {
            if (args.length > 3 || args.length < 3)
            {
                lund.printConsoleError("Incorrect parameters, needs loadmodel");
                lund.printConsoleError("modelname (xml/null)!");
            } 
            else
            {
                ZipFile zip = null;
                ZipEntry zipm = null;
                ZipEntry zipt = null;
                for (int i = 0; i < zips.size(); i++)
                {
                    for (int d = 0; d < zips.get(i).size(); d++)
                    {
                        lund.printConsoleInfo("Scanning: " + zips.get(i).getName());
                        zip = zips.get(i);
                        if (zip.getEntry(args[1]).getSize() != -1)
                        {
                            zipm = zip.getEntry(args[1]);
                            for (int f = 0; f < zips.size(); f++)
                            {
                                zip = zips.get(f);
                                for (int g = 0; g < zips.get(f).size(); g++)
                                {
                                    if (zip.getEntry(args[2]).getSize() != -1)
                                    {
                                        zipt = zip.getEntry(args[2]);
                                    }
                                }
                            }
                        }
                    }
                }
                if (zipt == null && zipm != null)
                {
                    Main.rendernode.attachChild(Main.spawning.createModel(Main.appref,
                            Main.player.getLocation(),
                            Main.appref.getAssetManager().loadModel(zipm.getName()),
                            "01ddf"));
                    lund.printConsoleInfo("Model found, loading..");
                } 
                else if (zipm != null)
                {
                    Main.rendernode.attachChild(Main.spawning.createModel(Main.appref,
                            Main.player.getLocation(),
                            Main.appref.getAssetManager().loadModel(zipm.getName()),
                            zipt.getName()));
                    lund.printConsoleInfo("Model found, along with it's xml, loading..");
                }
            }
        }
    }
    
    /*
    addZip:
    checks the validity of the specified zip, and then appends it to the zip list
    */
    private class addZip implements ConsoleCommand
    {
        @Override
        public void execute(final String[] args)
        {
            ZipFile zip = null;
            try 
            {
                zip = new ZipFile(args[1].toString());
            } 
            catch (IOException ex) 
            {
                lund.printConsoleError("The specified zip does not exist.");
            }
            if(zip != null)
            {
                Main.appref.getAssetManager().registerLocator(zip.getName(), ZipLocator.class.getName());
                zips.add(zip);
                lund.printConsoleInfo("Added: " + zip.getName());
            }
        }
    }
    
    /*
    buildMode:
    switch to change between build mode (placing objects etc) and play mode
    //TODO: add switch between third and first person for build mode
    */
    private class buildMode implements ConsoleCommand
    {
        @Override
        public void execute(final String[] args)
        {
            if(Main.player.isBuild == true)
            {
                lund.printConsoleInfo("Build Mode is now Off.");
                Main.rendernode.detachChild(ObjectPlayer.tracker);
                Main.player.isBuild = false;
            }
            else if (Main.player.isBuild == false)
            {
                lund.printConsoleInfo("Build Mode is now On.");
                Main.rendernode.attachChild(ObjectPlayer.tracker);
                Main.player.isBuild = true;
            }
        }
    }
    
    /*
    returnLoc:
    echoes the player's location
    */
    private class returnLoc implements ConsoleCommand
    {
        @Override
        public void execute(final String[] args)
        {
            lund.printConsoleInfo("Player at: " + Main.player.getLocation());
        }
    }
    
    /*
    spawnItem:
    length check, and then passes the given id through to the object_item class and spawns it
    */    
    private class spawnItem implements ConsoleCommand
    {
        @Override
        public void execute(final String[] args)
        {
            if(args.length < 2 || args.length > 2)
            {
                lund.printConsoleError("Incorrect parameters, needs spawnitem id");
            }
            else
            {
                ItemBase item = new ItemBase(Integer.parseInt(args[1]));
                item.spawn();
            }
        }
    }
    
    /*
    createServer:
    creates a server with the given port
    */
    private class createServer implements ConsoleCommand
    {
        @Override
        public void execute(final String[] args)
        {
            if(args.length < 2 || args.length > 2)
            {
                lund.printConsoleError("Incorrect parameters, needs createserver port");
            }
            else
            {
                Main.network.createServer(Integer.parseInt(args[1]));
            }
        }
    }
    
    /*
    connect:
    connects to a server with the given host and port
    */
    private class connect implements ConsoleCommand
    {
        @Override
        public void execute(final String[] args)
        {
            if(args.length < 3 || args.length > 3)
            {
                lund.printConsoleError("Incorrect parameters, needs connect host port");
            }
            else
            {
                Main.network.connectClient(args[1], Integer.parseInt(args[2]));
            }
        }
    }
    
    /*
    sendChat:
    sends the entire argument string to the server
    */
    private class sendChat implements ConsoleCommand
    {
        @Override
        public void execute(final String[] args)
        {
            if(Main.network.child != null)
            {
                Main.network.sendChat(Arrays.toString(args));
            }
        }
    }
    
    private class save_command implements ConsoleCommand
    {
        @Override
        public void execute(final String[] args)
        {
            if(args.length > 1)
            {
                FileHandler.save(args[1]);
            }
            else
            {
                lund.printConsoleError("Incorrect arguments, needs save filename");
            }
        }
    }
    
    private class load_command implements ConsoleCommand
    {
        @Override
        public void execute(final String[] args)
        {
            if(args.length > 1)
            {
                FileHandler.load(args[1]);
            }
            else
            {
                lund.printConsoleError("Incorrect arguments, needs save filename");
            }
        }
    }
    
    private class lookat implements ConsoleCommand
    {
        @Override
        public void execute(final String[] args)
        {
            if(args.length > 4 || args.length < 4)
            {
                lund.printConsoleError("Incorrect arguments, need lookat vector");
            }
            else
            {
                Main.player.cam.lookAt(new Vector3f(Integer.parseInt(args[1]),Integer.parseInt(args[2]),Integer.parseInt(args[3])), Main.appref.getCamera().getUp());
            }
        }
    }
    
    private class noclip implements ConsoleCommand
    {
        @Override
        public void execute(final String[] args)
        {
            if(Main.player.clipping == true)
            {
                Main.player.clipping = Main.player.setClip(false);
                lund.printConsoleInfo("Noclip set to: " + Main.player.clipping);
                Main.player.playerTeleport(Main.player.cam.getLocation());
            }
            else if (Main.player.clipping == false)
            {
                Main.player.clipping = Main.player.setClip(true);
                lund.printConsoleInfo("Noclip set to: " + Main.player.clipping);
            }
        }
    }
    
    /*
    load_commands:
    assigns all command variables and registers them
    */
    public void load_commands(Console con, Nifty nif)
    {
        con.output("Please wait, loading commands...");
        conCmd = new ConsoleCommands(nif,con);
        tp = new Teleport();
        help = new ShowCommand();
        ssao = new toggleSSAO();
        bloom = new toggleBloom();
        loadMap = new loadMap();
        build = new buildMode();
        loc = new returnLoc();
        LoadModel = new loadModel();
        addZip = new addZip();
        spawnItem = new spawnItem();
        createServer = new createServer();
        connect = new connect();
        sendChat = new sendChat();
        listnodes = new listNodes();
        save_command = new save_command();
        load_command = new load_command();
        lookat = new lookat();
        noclip = new noclip();
        conCmd.registerCommand("tp x y z", tp);
        conCmd.registerCommand("help", help);
        conCmd.registerCommand("ssao", ssao);
        conCmd.registerCommand("bloom", bloom);
        conCmd.registerCommand("loadmap map tex type", loadMap);
        conCmd.registerCommand("build", build);
        conCmd.registerCommand("loc", loc);
        conCmd.registerCommand("loadmodel model mat", LoadModel);
        conCmd.registerCommand("addzip zip", addZip);
        conCmd.registerCommand("spawnitem id", spawnItem);
        conCmd.registerCommand("createserver", createServer);
        conCmd.registerCommand("connect", connect);
        conCmd.registerCommand("sendchat", sendChat);
        conCmd.registerCommand("listnodes", listnodes);
        conCmd.registerCommand("save filename", save_command);
        conCmd.registerCommand("load filename", load_command);
        conCmd.registerCommand("lookat vector", lookat);
        conCmd.registerCommand("noclip", noclip);
        conCmd.enableCommandCompletion(true);
    }
}
